package com.duck.duckchatbackend.websocket.netty;


import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * HandlerHeartBeat类继承自ChannelDuplexHandler，用于处理心跳逻辑
 * 心跳机制主要用于检测客户端和服务端之间的连接是否处于活跃状态，通过发送心跳包来维持连接的活跃
 */
public class HandlerHeartBeat extends ChannelDuplexHandler {
    // 定义日志对象，用于记录心跳处理过程中的日志信息
    private static final Logger logger = LoggerFactory.getLogger(HandlerHeartBeat.class);

    /**
     * 当用户事件被触发时，此方法被调用
     * 主要用于处理读空闲和写空闲的事件，以实现心跳机制
     *
     * @param ctx 通道处理上下文，提供了与通道交互的操作方法
     * @param evt 触发的事件对象，当evt为IdleStateEvent类型时，表示通道处于空闲状态
     * @throws Exception 如果处理事件时发生异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        // 判断事件是否为IdleStateEvent类型，此类事件表示通道已经空闲了一段时间
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            // 当读取操作空闲时，即在指定时间内没有接收到数据，认为客户端已经断开连接，记录日志并关闭通道
            if (e.state() == IdleState.READER_IDLE) {
                //根据通道ID获取用户ID
                Channel channel = ctx.channel();
                Attribute<String> attribute = channel.attr(AttributeKey.valueOf(channel.id().toString()));
                String userId = attribute.get();
                //logger.info("用户{}心跳超时", userId);
                ctx.close();
                // 当写操作空闲时，即在指定时间内没有发送数据，发送一个心跳包以维持连接活跃
            } else if (e.state() == IdleState.WRITER_IDLE) {
                ctx.writeAndFlush("heart");
            }
        }
    }
}
